package org.xhy.sniffer.trace;


import org.xhy.sniffer.config.Config;
import org.xhy.sniffer.ids.IdGenerate;

import java.util.*;

public class TraceSegment {


    private int segmentId;

    private String serviceName;

    private String serviceId;

    private Stack<AbstractSpan> spans;

    private Date startTime;

    private Date endTime;

    public TraceSegment(){
        this.segmentId = -1;
        this.startTime = new Date();
        this.spans = new Stack<>();
        this.serviceName = Config.getProperty("serviceName");
        this.serviceId = Config.getProperty("serviceId");
    }

    public AbstractSpan activeSpanStack(){
        return spans.peek();
    }

    public AbstractSpan createEntrySpan(String operationName, CommentDefine comment,String peer){
        EntrySpan entrySpan = new EntrySpan(operationName,comment,peer);
        if (spans.isEmpty()){
            String traceId = IdGenerate.generateId();
            entrySpan.setTraceId(traceId);
            entrySpan.setSpanId(-1);
        }else {
            AbstractSpan peek = spans.peek();
            entrySpan.setParentSpanId(peek.getSpanId());
            entrySpan.setTraceId(peek.getTraceId());
            entrySpan.setSpanId(peek.getSpanId()+1);
        }
        spans.add(entrySpan);
        return entrySpan;
    }

    // 记录 segment 最后一个 span 情况
    public AbstractSpan createExitSpan(){
        AbstractSpan exitEntry = spans.pop();
        if (spans.isEmpty()){
            endTime = new Date();
        }
        finish();
        return exitEntry;
    }

    private void finish(){
        if (spans.isEmpty()){
            TraceContext.ListenerManager.notifyFinish(this);
        }
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("TraceSegment {")
                .append("\n  Segment ID: ").append(segmentId)
                .append("\n  Service Name: ").append(serviceName)
                .append("\n  Service ID: ").append(serviceId)
                .append("\n  Start Time: ").append(startTime)
                .append("\n  End Time: ").append(endTime)
                .append("\n  Spans: [");

        if (spans != null && !spans.isEmpty()) {
            for (AbstractSpan span : spans) {
                sb.append("\n    ").append(span.toString());
            }
            sb.append("\n  ]");
        } else {
            sb.append(" No spans ]");
        }

        sb.append("\n}");
        return sb.toString();
    }

    public String getTraceId(){
        return spans.peek().getTraceId();
    }

    public int getSegmentId() {
        return segmentId;
    }

    public String getServiceName() {
        return serviceName;
    }

    public String getServiceId() {
        return serviceId;
    }

    public Stack<AbstractSpan> getSpans() {
        return spans;
    }

    public Date getStartTime() {
        return startTime;
    }

    public Date getEndTime() {
        return endTime;
    }

}
